<template>
  <view class="notice-bar">
    <view v-if="showNoticeBar" class="notice-list">
      <view
        class="notice-item"
        v-for="(notice, index) in noticeList"
        :key="index"
        :class="getNoticeClassName(notice.color)"
      >
        <image
          v-if="notice.closable"
          class="close-icon"
          hover-class="hovering"
          mode="aspectFit"
          :src="getNoticeDissmissIcon(notice.color)"
          @click.stop="removeNotice(notice)"
        />
        <view class="notice-body">
          <view class="title">{{ notice.description }}</view>
          <view v-if="notice.action" class="action-link" hover-class="hovering" @click.stop="handleActionLink(notice)">
            <text class="action-text">{{ notice.action.linkText }}</text>
            <image class="action-arrow" mode="aspectFit" :src="getNoticeMoreIcon(notice.color)" />
          </view>
        </view>
      </view>
    </view>
  </view>
  <NoticeActionModal
    v-model:show="showAction"
    :control="control"
    :notice="actionUsedNotice"
    :notice-control="noticeControl"
  />
</template>

<script setup lang="ts">
import { NoticeColor, ActionType, type Notice } from '@/types/notice'
import { useEnvStore } from '@/store/env'
import type { BaseController } from '@/controller/BaseAppliance/definition'
import NoticeActionModal from '@/pages/appliance/view/notification/noticeAction.vue'
import { jumpMP, toPage, useUniEvent } from '@/utils/mpHelper'
import { trackEvent, TrackType } from '@/dataReport/tracks'
import { useNoticeControl, type NoticeLinkCallback } from './useNoticeControl'
import { safeTrack } from '@/dataReport/dataReportUtil'
import { NoticePreventActionInvoked, OpenNoticeActionByApiError, NoticeAdded } from '@/constants/UniEventKeys'
import { NoticeBarErrorInfo, NoticeBarProductTypes } from './noticeBarError'
import { useControlState } from '@/controller/BaseAppliance/useControl'
export type ShouldPreventAction = (notice: Notice) => Promise<boolean>

const props = defineProps<{
  control: BaseController.Control
  // 外部传入的 action支持调用的方法
  externalMethods?: Record<string, NoticeLinkCallback>
  // 是否阻止action
  preventAction?: ShouldPreventAction
  // 强制显示顶部通知栏
  showForced?: boolean
}>()

const { showControlView } = useControlState(props.control)
const envStore = useEnvStore()
const noticeBarTop = computed(() => `${envStore.titleBarHeight}px`)
const noticeList = computed<Notice[]>(() => props.control.store.noticeList)
const showNoticeBar = computed(() => {
  if (props.showForced) return true
  return showControlView.value && noticeList.value.length > 0
})

const noticeControl = useNoticeControl(props.control, {
  externalMethods: props.externalMethods || {},
})

/**
 * 删除
 */
function removeNotice(notice: Notice) {
  props.control.store.removeNotice(notice)
}

/**
 * 样式处理
 */
const noticeClassNameMap: Record<NoticeColor, string> = {
  [NoticeColor.Normal]: 'is-normal',
  [NoticeColor.Warning]: 'is-warning',
  [NoticeColor.Danger]: 'is-danger',
}
function getNoticeClassName(color: NoticeColor) {
  return noticeClassNameMap[color]
}
function getNoticeDissmissIcon(color: NoticeColor) {
  if (color === NoticeColor.Normal) return '/static/NoticeDissmissLight.png'
  if (color === NoticeColor.Warning) return '/static/NoticeDissmissDark.png'
  if (color === NoticeColor.Danger) return '/static/NoticeDissmissLight.png'
  return ''
}
function getNoticeMoreIcon(color: NoticeColor) {
  if (color === NoticeColor.Normal) return '/static/NoticeMoreLight.png'
  if (color === NoticeColor.Warning) return '/static/NoticeMoreDark.png'
  if (color === NoticeColor.Danger) return '/static/NoticeMoreLight.png'
  return ''
}

/**
 * 处理Action
 */
const showAction = ref(false)
const actionUsedNotice = ref<Notice | null>(null)
async function handleActionLink(notice: Notice) {
  if (!notice.action) return

  // 判断是否需要阻止默认处理
  if (typeof props.preventAction === 'function') {
    let shouldPrevent = false
    try {
      shouldPrevent = await props.preventAction(notice)
    } catch (e) {
      console.error(e)
    }
    // 需要阻止默认处理
    if (shouldPrevent) {
      // 触发prevent事件
      uni.$emit(NoticePreventActionInvoked, notice)
      return
    }
  }

  const action = notice.action

  switch (action.type) {
    case ActionType.RichText:
      return toPage('/pages/my/guideVideo/guideVideo', {
        id: action.articleId,
        type: action.articleType,
      })
    // 跳转小程序内部页面
    case ActionType.ToPage: {
      const landingPage = action.landingPage.startsWith('/') ? action.landingPage : `/${action.landingPage}`
      safeTrack(() => {
        trackEvent(
          'click_navigation_bar',
          {
            inApp_notification_id: action.landingPage.split('?')[1].split('&')[0].split('=')[1],
          },
          TrackType.ApplianceDetail,
          notice.key
        )
      })
      return toPage(landingPage)
    }
    // 跳转外部小程序
    case ActionType.ToOtherMP: {
      safeTrack(() => {
        trackEvent(
          'click_navigation_bar',
          {
            inApp_notification_id: action.landingPage.split('?')[1].split('&')[0].split('=')[1],
          },
          TrackType.ApplianceDetail,
          notice.key
        )
      })
      let appliance_type = props.control.store._datasource.type
      if (NoticeBarProductTypes.includes(appliance_type)) {
        if (Object.keys(NoticeBarErrorInfo).includes(notice.key)) {
          let appliance_vib = props.control.store._datasource.vib
          let errorDesFlag = appliance_type === 'Dishwasher' && notice.key === 'BSH.Common.Event.LowWaterPressure'
          let desc = errorDesFlag ? '供水水压过低' : NoticeBarErrorInfo[notice.key]
          let descKey = notice.key
          let params = { productmodal: appliance_vib, desc, descKey }
          return jumpMP(action.appid, action.landingPage, params, 'Appliance.NoticeBar.AfterService.ToOtherPM')
        } else {
          return jumpMP(action.appid, action.landingPage, {}, 'Appliance.NoticeBar.General.ToOtherPM')
        }
      } else {
        return jumpMP(action.appid, action.landingPage, {}, 'Appliance.NoticeBar.General.ToOtherPM')
      }
    }
    case ActionType.InvokeMethod: {
      safeTrack(() => {
        trackEvent('click_navigation_bar', {}, TrackType.ApplianceDetail, notice.key)
      })
      return noticeControl.onLinkClick(notice, action.method)
    }
    // 显示Action
    default: {
      actionUsedNotice.value = notice
      showAction.value = true
      safeTrack(() => {
        trackEvent(
          'click_navigation_bar',
          {
            inApp_notification_id: '',
          },
          TrackType.ApplianceDetail,
          notice.key
        )
      })
      break
    }
  }
}
useUniEvent(OpenNoticeActionByApiError, (notice: Notice) => handleActionLink(notice))
useUniEvent(NoticeAdded, (notice: Notice) => {
  // 立即触发Action
  if (notice.triggerActionImmediate === true) {
    handleActionLink(notice)
  }
})

// 通知列表变化时 判断是否需要同步关闭已消除的通知
watch(
  () => props.control.store.rawNoticeList, // rawNoticeList 包含立即触发的通知
  (list) => {
    if (!showAction.value || actionUsedNotice.value === null) return

    // 记录之前开启弹框的 key value
    const { key: previousKey, value: previousValue } = actionUsedNotice.value

    // 在最新通知列表里查找匹配key的通知
    const latestNotice = list.find((notice) => notice.key === previousKey)

    // 最新列表里不存在相同key 或 不存在相同value 时 隐藏弹框 重置参数
    if (!latestNotice || latestNotice.value !== previousValue) {
      showAction.value = false
      actionUsedNotice.value = null
    }
  }
)
</script>

<style lang="less">
.notice-list {
  position: fixed;
  top: v-bind(noticeBarTop);
  left: 0;
  width: 100%;
  max-height: calc(100vh - v-bind(noticeBarTop) - constant(safe-area-inset-bottom));
  max-height: calc(100vh - v-bind(noticeBarTop) - env(safe-area-inset-bottom));
  line-height: 80rpx;
  overflow: auto;
  z-index: 10;
}
.notice-item {
  display: flex;
  padding: 20rpx 24rpx;
  backdrop-filter: blur(16rpx);
  &.is-normal {
    background-color: rgba(var(--dark-vector), 0.8);
    color: #ffffff;
  }
  &.is-warning {
    background-color: rgba(var(--warning-vector), 0.8);
    color: var(--dark-color);
  }
  &.is-danger {
    background-color: rgba(var(--danger-vector), 0.8);
    color: #ffffff;
    .notice-body .title {
      font-weight: 600;
    }
  }
  + .notice-item {
    margin-top: 4rpx;
  }
  .close-icon {
    width: 36rpx;
    // height: 36rpx;
    height: 40rpx; // 与第一行平齐
    margin-right: 16rpx;
    flex-shrink: 0;
    &.hovering {
      filter: brightness(0.8);
    }
  }
  .notice-body {
    flex: 1;
    // display: flex;
    // align-items: center;
    // flex-wrap: wrap;
    line-height: 1;
    font-weight: 400;
    font-size: 32rpx;
    line-height: 40rpx;
    .title {
      margin-right: 8rpx;
      display: inline;
    }
  }
}
.action-link {
  align-items: center;
  text-decoration: underline;
  white-space: nowrap;
  display: inline-block;
  &.hovering {
    filter: opacity(0.8);
  }
  .action-arrow {
    width: 28rpx;
    height: 24rpx;
    margin-left: 6rpx;
  }
}
</style>
